/**
 *    @file       synqueue.h
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       12/13/2012 05:05:53 PM
 *
 *    @author     Theophilus, wangtf418@gmail.com
 */
#ifndef _BF_SYNQUEUE_H_
#define _BF_SYNQUEUE_H_
#include <pthread.h>
#include <semaphore.h>
#include <deque>

//2^18 = 262144
#define MAX_SYNQUEUE_LEN 262144

template<typename _Telem>
class synqueue
{
public:
	synqueue(bf_uint_t maxsize = MAX_SYNQUEUE_LEN)
		: m_maxsize(maxsize)
	{
		sem_init(&m_sem_write, 0, m_maxsize);
		sem_init(&m_sem_read, 0, 0);
		pthread_mutex_init(&m_mutex_lock, NULL);
	}

	~synqueue()
	{
		sem_destroy(&m_sem_read);
		sem_destroy(&m_sem_write);
		pthread_mutex_destroy(&m_mutex_lock);
	}

public:
	bf_int_t put(_Telem *elem)
	{
		sem_wait(&m_sem_write);
		pthread_mutex_lock(&m_mutex_lock);
		m_queue.push_back(elem);
		pthread_mutex_unlock(&m_mutex_lock);
		return sem_post(&m_sem_read);
	}

	bf_int_t put(_Telem *elem, bf_int_t ifpri)
	{	
		sem_wait(&m_sem_write);
		pthread_mutex_lock(&m_mutex_lock);
		if (ifpri)
		{
			m_queue.push_front(elem);
		}
		else
		{
			m_queue.push_back(elem);
		}
		pthread_mutex_unlock(&m_mutex_lock);
		return sem_post(&m_sem_read);
	}

	_Telem* get()
	{
		_Telem *elem = NULL;
		sem_wait(&m_sem_read);
		pthread_mutex_lock(&m_mutex_lock);
		if (m_queue.begin() != m_queue.end())
		{
			elem = m_queue.front();
			m_queue.pop_front();
		}
		pthread_mutex_unlock(&m_mutex_lock);
		sem_post(&m_sem_write);
		return elem;
	}

	bf_size_t size()
	{
		bf_size_t queue_size = 0;
		pthread_mutex_lock(&m_mutex_lock);
		queue_size = m_queue.size();
		pthread_mutex_unlock(&m_mutex_lock);
		return queue_size;
	}
	
	bf_uint_t get_maxsize()
	{
		return m_maxsize;
	}

private:
	bf_uint_t m_maxsize;
	std::deque<_Telem*> m_queue;
	sem_t m_sem_read;
	sem_t m_sem_write;
	pthread_mutex_t m_mutex_lock;
};


#endif

